package com.baidu.mpks.usergroup.service;

import com.baidu.mpks.common.RedisClient;
import com.baidu.mpks.exception.BusinessException;
import com.baidu.mpks.permission.service.PermissionCacheService;
import com.baidu.mpks.role.service.RoleService;
import com.baidu.mpks.user.dao.UserDao;
import com.baidu.mpks.user.domain.User;
import com.baidu.mpks.user.service.UserService;
import com.baidu.mpks.user.vo.UserParam;
import com.baidu.mpks.usergroup.dao.UserGroupDao;
import com.baidu.mpks.usergroup.domain.UserGroup;
import com.baidu.mpks.usergroup.dto.Resources;
import com.baidu.mpks.usergroup.dto.UserGroupDto;
import com.baidu.mpks.usergroup.enums.ResourceType;
import com.baidu.mpks.usergroup.enums.UserGroupType;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Lists;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.logging.log4j.ThreadContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class UserGroupServiceImpl implements UserGroupService {
    private static final Logger log = LoggerFactory.getLogger(UserGroupServiceImpl.class);
    @Autowired
    private UserGroupDao userGroupDao;
    @Autowired
    private UserService userService;
    @Autowired
    UserDao userDao;
    @Autowired
    RoleService roleService;
    @Autowired
    RedisClient redisClient;
    @Autowired
    PermissionCacheService permissionCacheService;
    @Autowired
    ContentTagService contentTagService;
    private static String userTagPrefix = "user:tag:";

    public UserGroupServiceImpl() {
    }

    public UserGroupDto addGroup(UserGroupDto userGroupDto) {
        UserGroup parentGroup = this.checkAndGetUserGroup(userGroupDto.getParentId());
        UserGroup existGroup = this.getUserGroupByNameAndType(userGroupDto.getName(), parentGroup.getType());
        if (existGroup != null) {
            throw new BusinessException("当前组名重复，请修改");
        } else {
            UserGroup userGroup = new UserGroup();
            userGroup.setParentId(userGroupDto.getParentId());
            userGroup.setDescription(userGroupDto.getDescription());
            userGroup.setType(parentGroup.getType());
            userGroup.setName(userGroupDto.getName());
            userGroup.setEdit(1);
            userGroup.setDelete(1);
            this.userGroupDao.addGroup(userGroup);

            try {
                ThreadContext.put("operationContent", "机构新增：" + (new ObjectMapper()).writeValueAsString(userGroup));
            } catch (JsonProcessingException var6) {
                var6.printStackTrace();
            }

            return this.getUserGroupDto(userGroup);
        }
    }

    public UserGroup getUserGroupByNameAndType(String name, String type) {
        return this.userGroupDao.getGroupByNameAndType(name, type);
    }

    public List<UserGroupDto> getGroupList(Integer parentId) {
        List<UserGroup> userGroups = this.userGroupDao.getGroupsByParentId(parentId);
        return (List)userGroups.stream().map(this::getUserGroupDto).collect(Collectors.toList());
    }

    public List<UserGroupDto> getGroupList(String type) {
        UserGroup rootGroup = this.userGroupDao.getRootGroupByType(type);
        if (rootGroup == null) {
            throw new BusinessException(type + "根组不存在");
        } else {
            List<UserGroup> list = new LinkedList();
            list.add(rootGroup);
            this.getSubGroup(rootGroup.getId(), list);
            return (List)list.stream().map(this::getUserGroupDto).collect(Collectors.toList());
        }
    }

    public void getSubGroup(Integer parentId, List<UserGroup> list) {
        List<UserGroup> userGroups = this.userGroupDao.getGroupsByParentId(parentId);
        if (CollectionUtils.isNotEmpty(userGroups)) {
            Iterator var4 = userGroups.iterator();

            while(var4.hasNext()) {
                UserGroup userGroup = (UserGroup)var4.next();
                if (!list.contains(userGroup)) {
                    list.add(userGroup);
                    this.getSubGroup(userGroup.getId(), list);
                }
            }
        }

    }

    public UserGroupDto getRootGroup(String type) {
        UserGroup userGroup = this.userGroupDao.getRootGroupByType(type);
        if (userGroup == null) {
            throw new BusinessException(type + "根组不存在");
        } else {
            return this.getUserGroupDto(userGroup);
        }
    }

    @Transactional
    public void deleteGroup(Integer groupId) {
        UserGroup userGroup = this.checkAndGetUserGroup(groupId);
        if (!this.hasUser(groupId) && !this.hasGroup(groupId)) {
            this.userGroupDao.deleteById(groupId);
            this.userGroupDao.removeResourcesByGroupId(groupId);
            this.userGroupDao.removeRolesByGroupId(groupId);

            try {
                ThreadContext.put("operationContent", "机构删除：" + (new ObjectMapper()).writeValueAsString(userGroup));
            } catch (JsonProcessingException var4) {
                var4.printStackTrace();
            }

        } else {
            throw new BusinessException("当前组下存在子组或用户，不允许删除");
        }
    }

    public UserGroupDto updateGroup(UserGroupDto userGroupDto) {
        UserGroup userGroup = new UserGroup();
        userGroup.setId(userGroupDto.getId());
        userGroup.setName(userGroupDto.getName());
        userGroup.setDescription(userGroupDto.getDescription());
        userGroup.setUpdateTime(new Date());
        this.userGroupDao.updateGroup(userGroup);

        try {
            ThreadContext.put("operationContent", "机构更新：" + (new ObjectMapper()).writeValueAsString(userGroup));
        } catch (JsonProcessingException var4) {
            var4.printStackTrace();
        }

        return null;
    }

    public UserGroupDto getGroupInfo(Integer groupId) {
        UserGroup userGroup = this.checkAndGetUserGroup(groupId);
        UserGroupDto userGroupDto = this.getUserGroupDto(userGroup);
        Set<Integer> subGroups = new HashSet();
        Set<String> users = new HashSet();
        userGroupDto.setHasGroupCount(this.getSubGroupCount(groupId, subGroups).size());
        userGroupDto.setHasUserCount(this.getUserCount(groupId, users).size());
        return userGroupDto;
    }

    public Set<UserGroup> searchGroup(String name, String type) {
        Set<UserGroup> set = new HashSet();
        List<UserGroup> userGroups = this.userGroupDao.getGroupByLikeNameAndType(name, type);
        if (CollectionUtils.isNotEmpty(userGroups)) {
            Iterator var5 = userGroups.iterator();

            while(var5.hasNext()) {
                UserGroup userGroup = (UserGroup)var5.next();
                set.add(userGroup);
                this.recurGroup(userGroup.getParentId(), set);
            }
        }

        return set;
    }

    public void recurGroup(Integer groupId, Set<UserGroup> set) {
        if (groupId != 0) {
            UserGroup userGroup = this.userGroupDao.getGroupById(groupId);
            if (userGroup != null) {
                set.add(userGroup);
                this.recurGroup(userGroup.getParentId(), set);
            }
        }

    }

    public UserGroup checkAndGetUserGroup(Integer groupId) {
        UserGroup userGroup = this.userGroupDao.getGroupById(groupId);
        if (userGroup == null) {
            throw new BusinessException("组不存在 --->" + groupId);
        } else {
            return userGroup;
        }
    }

    public UserGroupDto addResources(Integer groupId, String type, List<Resources> tags) {
        this.checkAndGetUserGroup(groupId);
        this.userGroupDao.addResourcesByGroupId(groupId, type, tags);
        return null;
    }

    public void removeResourcesById(Integer groupId, String type, List<Integer> tagIds) {
        if (groupId != null) {
            this.userGroupDao.removeResourcesByGroupIdAndResourceId(groupId, type, tagIds);
        }

    }

    public void removeResourcesByName(Integer groupId, String type, List<String> tagNames) {
        if (groupId != null) {
            this.userGroupDao.removeResourcesByGroupIdAndResourceName(groupId, type, tagNames);
        }

    }

    @Transactional
    public List<Resources> updateResourcesByGroup(Integer groupId, String type, List<Resources> resources) {
        this.checkAndGetUserGroup(groupId);
        this.userGroupDao.removeResourcesByGroupIdAndType(groupId, type);
        if (CollectionUtils.isNotEmpty(resources)) {
            this.userGroupDao.addResourcesByGroupId(groupId, type, resources);
        }

        return null;
    }

    public List<Resources> getResourcesByGroup(Integer groupId, String type) {
        this.checkAndGetUserGroup(groupId);
        List<Resources> resourcesList = this.userGroupDao.getResourcesByGroup(groupId, type);
        resourcesList = this.filterResources(resourcesList, type);
        this.updateResourcesByGroup(groupId, type, resourcesList);
        return resourcesList;
    }

    private List<Resources> filterResources(List<Resources> resources, String type) {
        if (ResourceType.TAG.getName().equals(type)) {
            Map<String, Resources> resourcesMap = (Map)resources.stream().collect(Collectors.toMap(Resources::getName, Function.identity()));
            Set<String> existingTags = this.contentTagService.getExistingTags(new ArrayList(resourcesMap.keySet()));
            List<Resources> result = new ArrayList(existingTags.size());
            existingTags.forEach((tag) -> {
                result.add(resourcesMap.get(tag));
            });
            return result;
        } else {
            return resources;
        }
    }

    public UserGroupDto addRoles(Integer groupId, List<Resources> roles) {
        this.checkAndGetUserGroup(groupId);
        if (CollectionUtils.isNotEmpty(roles)) {
            this.userGroupDao.addRolesByGroupId(groupId, roles);
        }

        return null;
    }

    @Transactional
    public UserGroupDto updateRoles(Integer groupId, List<Resources> roles) {
        this.checkAndGetUserGroup(groupId);
        this.userGroupDao.removeRolesByGroupId(groupId);
        this.addRoles(groupId, roles);
        this.permissionCacheService.clearPermissionAll();
        return null;
    }

    public List<UserGroup> getUserGroupsByUserId(String userId) {
        return this.userGroupDao.getGroupsByUserId(userId);
    }

    public List<UserGroup> getUserGroupsByUserId(String userId, String type) {
        return this.userGroupDao.getGroupsByUserIdAndGroupType(userId, type);
    }

    public Set<UserGroup> getUserGroupsByUserIds(List<String> userIds, String type) {
        return this.userGroupDao.getGroupsByUserIdsAndGroupType(userIds, type);
    }

    public void removeRoles(Integer groupId, List<Integer> roleIds) {
        if (groupId != null) {
            this.userGroupDao.removeRolesByGroupIdAndRoleId(groupId, roleIds);
        }

    }

    public List<Resources> getRolesByGroup(Integer groupId) {
        this.checkAndGetUserGroup(groupId);
        return this.userGroupDao.getRolesByGroup(groupId);
    }

    public List<Resources> getInheritRolesByGroup(Integer groupId, boolean includeCur) {
        Set<UserGroup> userGroupSet = new HashSet();
        UserGroup userGroup = this.userGroupDao.getGroupById(groupId);
        if (userGroup != null) {
            if (includeCur) {
                this.recurGroup(groupId, userGroupSet);
            } else {
                this.recurGroup(userGroup.getParentId(), userGroupSet);
            }
        }

        List<Resources> inheritRoleList = new ArrayList();
        Iterator var6 = userGroupSet.iterator();

        while(var6.hasNext()) {
            UserGroup e = (UserGroup)var6.next();
            List<Resources> tempResList = this.getRolesByGroup(e.getId());
            if (tempResList != null) {
                inheritRoleList.addAll(tempResList);
            }
        }

        inheritRoleList = (List)inheritRoleList.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> {
            return new TreeSet(Comparator.comparing(Resources::getId));
        }), ArrayList::new));
        return inheritRoleList;
    }

    public List<UserGroup> getGroupByRoleId(Integer roleId) {
        return roleId != null ? this.userGroupDao.getGroupByRoleId(roleId) : null;
    }

    public UserGroupDto addUser(Integer groupId, String userId) {
        UserGroup userGroup = this.checkAndGetUserGroup(groupId);
        if (userGroup.getType().equals(UserGroupType.DEPARTMENT.getName())) {
            List<UserGroup> userGroups = this.userGroupDao.getGroupsByUserIdAndGroupType(userId, userGroup.getType());
            if (CollectionUtils.isNotEmpty(userGroups)) {
                throw new BusinessException("该用户" + userId + "已存在部门关系，不允许添加该用户");
            }
        }

        this.userGroupDao.addUsersByGroupId(groupId, Lists.newArrayList(new String[]{userId}));
        return null;
    }

    public List<UserParam> addUsers(Integer groupId, List<UserParam> users) {
        UserGroup userGroup = this.checkAndGetUserGroup(groupId);
        List<UserParam> illegalUsers = new LinkedList();
        if (userGroup.getType().equals(UserGroupType.DEPARTMENT.getName())) {
            List<String> legalUserIds = new LinkedList();

            for(Iterator var6 = users.iterator(); var6.hasNext(); this.userGroupDao.addUsersByGroupId(groupId, legalUserIds)) {
                UserParam user = (UserParam)var6.next();
                List<UserGroup> userGroups = this.userGroupDao.getGroupsByUserIdAndGroupType(user.getUserId(), userGroup.getType());
                if (CollectionUtils.isNotEmpty(userGroups)) {
                    illegalUsers.add(user);
                    log.error("该用户" + user.getUserId() + "已存在部门关系，不允许添加该用户");
                } else {
                    legalUserIds.add(user.getUserId());
                }
            }
        } else {
            List<String> userIds = (List)users.stream().map(UserParam::getUserId).collect(Collectors.toList());
            this.userGroupDao.addUsersByGroupId(groupId, userIds);
        }

        return illegalUsers;
    }

    public void removeUsers(Integer groupId, List<String> userIds) {
        if (groupId != null) {
            this.userGroupDao.removeUsersByGroupId(groupId, userIds);
        }

    }

    public void removeUserByUserId(String userId) {
        this.userGroupDao.removeUserByUserId(userId);
    }

    public void removeUsersByType(String type, List<String> userIds) {
        this.userGroupDao.removeUsersByType(type, userIds);
    }

    public Map<String, Object> getUsersByGroup(Integer groupId, Integer pageNum, Integer pageSize) {
        Map<String, Object> result = new HashMap();
        List<User> userList = new ArrayList();
        Set<String> userIds = this.userGroupDao.getUserIdsByGroupId(groupId, (pageNum - 1) * pageSize, pageSize);
        if (CollectionUtils.isNotEmpty(userIds)) {
            userList = this.userDao.findByUserIds(userIds);
            Iterator var7 = ((List)userList).iterator();

            while(var7.hasNext()) {
                User user = (User)var7.next();
                List<Integer> roleIdList = this.userService.getUserAllRoleIds(user.getUserId());
                String roleIds = (String)roleIdList.stream().map((e) -> {
                    return e.toString();
                }).collect(Collectors.joining(","));
                user.setRoleIds(roleIds);
                user.setPassword((String)null);
            }
        }

        Integer total = this.userGroupDao.getUserIdsByGroupIdCount(groupId);
        result.put("pageSize", pageSize);
        result.put("pageNumber", pageNum);
        result.put("list", userList);
        result.put("totalSize", total);
        return result;
    }

    private UserGroupDto getUserGroupDto(UserGroup userGroup) {
        UserGroupDto userGroupDto = new UserGroupDto();
        if (userGroup != null) {
            try {
                BeanUtils.copyProperties(userGroupDto, userGroup);
                userGroupDto.setHasGroup(this.hasGroup(userGroup.getId()));
            } catch (InvocationTargetException | IllegalAccessException var4) {
                log.error("" + var4);
            }
        }

        return userGroupDto;
    }

    private Boolean hasGroup(Integer groupId) {
        List<UserGroup> userGroups = this.userGroupDao.getGroupsByParentId(groupId);
        return CollectionUtils.isNotEmpty(userGroups);
    }

    private Boolean hasUser(Integer groupId) {
        Set<String> userIds = this.userGroupDao.getUserIdsByGroupId(groupId, (Integer)null, (Integer)null);
        return CollectionUtils.isNotEmpty(userIds);
    }

    private Set<Integer> getSubGroupCount(Integer groupId, Set<Integer> subGroupSet) {
        List<UserGroup> userGroups = this.userGroupDao.getGroupsByParentId(groupId);
        if (CollectionUtils.isNotEmpty(userGroups)) {
            Iterator var4 = userGroups.iterator();

            while(var4.hasNext()) {
                UserGroup userGroup = (UserGroup)var4.next();
                subGroupSet.add(userGroup.getId());
                this.getSubGroupCount(userGroup.getId(), subGroupSet);
            }
        }

        return subGroupSet;
    }

    private Set<String> getUserCount(Integer groupId, Set<String> userSet) {
        List<UserGroup> userGroups = this.userGroupDao.getGroupsByParentId(groupId);
        Set<String> users = this.userGroupDao.getUserIdsByGroupId(groupId, (Integer)null, (Integer)null);
        if (CollectionUtils.isNotEmpty(users)) {
            userSet.addAll(users);
        }

        if (CollectionUtils.isNotEmpty(userGroups)) {
            Iterator var5 = userGroups.iterator();

            while(var5.hasNext()) {
                UserGroup userGroup = (UserGroup)var5.next();
                this.getUserCount(userGroup.getId(), userSet);
            }
        }

        return userSet;
    }
}